package pl.edu.pw.MidEmu.Sensing.Processing;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;

import pl.edu.pw.MidEmu.Sensing.Sensors.ASensor;

/**
 * Class responsible for inter-process communication.
 * Sends sensors reading over socket to MIDAS enable application
 * 
 * @author Mateusz Starodab
 *
 */
public class ProcessingAlgorithmServer extends Thread
{
	private boolean runCondition = true;

	private ArrayList<ASensor> sensors;

	private ServerSocket serverSocket;

	/**
	 * Removes sensor from this server
	 * Used when running sensor is removed from virtual node 
	 * @param selectedSensor Sensor to be removed
	 */
	public void deregisterSensor(ASensor selectedSensor)
	{
		if (sensors.contains(selectedSensor))
			sensors.remove(selectedSensor);
	}

	/**
	 * Gets IP address of this Sensor Server
	 * @return IP address
	 */
	public String getSensorIP()
	{
		if (serverSocket == null)
			return "";
		return serverSocket.getInetAddress().getHostAddress();
	}

	/**
	 * Gets Sensor Server pot
	 * @return port
	 */	
	public int getSensorPort()
	{
		if (serverSocket == null)
			return -1;
		return serverSocket.getLocalPort();
	}


	/**
	 * Initializates communication socket
	 * @param ipAddress IP address on which to listen for incoming client connections
	 */
	public void init(String ipAddress)
	{
		sensors = new ArrayList<ASensor>();
		try
		{
			serverSocket = new ServerSocket(0, 0, InetAddress.getByName(ipAddress));
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
	}
	
	/**
	 * Processes request comming through socket from client
	 * @param readLine Line to process
	 * @param out Response stream
	 */
	private void ProcessLine(String readLine, PrintWriter out)
	{
		String[] tokens = readLine.split(";");
		if (tokens[0].equals("LIST"))
		{
			StringBuilder outLine = new StringBuilder();

			for (ASensor sensor : sensors)
			{
				outLine.append("SENSOR;");
				outLine.append(sensor.getId());
				outLine.append(";");
				outLine.append(sensor.getCkbName());
				outLine.append(";");
			}

			out.println(outLine.toString());
		}
		else if (tokens[0].equals("READ"))
		{
			for (ASensor sensor : sensors)
			{
				if (sensor.getId().equals(tokens[1]))
				{
					out.println(sensor.getValue().getValueAsFloat());
					return;
				}
			}

		}

	}

	/**
	 * Registers sensor for use with this Sensor Server
	 * @param sensor Sensor to register
	 */
	public void registerSensor(ASensor sensor)
	{
		if (!sensors.contains(sensor))
			sensors.add(sensor);
	}

	/**
	 * Starts thread responsible for listening to incoming requests
	 */
	@Override
	public void run()
	{
		try
		{
			while (runCondition)
			{
				Socket client = serverSocket.accept();
				PrintWriter out = new PrintWriter(client.getOutputStream(), true);
				BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));

				String fromClient = in.readLine();

				if (fromClient != null)
					ProcessLine(fromClient, out);

				in.close();
				out.close();
				client.close();
			}
		}
		catch (SocketException ex)
		{
			if (runCondition)
				ex.printStackTrace();
		}
		catch (IOException ex)
		{
			if (runCondition)
				ex.printStackTrace();
		}
	}

	/**
	 * Terminates Sensor Server
	 */
	public void terminate()
	{
		if (serverSocket == null)
			return;

		runCondition = false;

		try
		{
			serverSocket.close();
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
	}
}
